# -*- coding: utf-8 -*-

import datetime
import uuid

from sqlalchemy.orm.dynamic import AppenderMixin

from face_recognition.models import BaseModelMixin


class SerializeMixin(object):
    'Mixin for retrieving public fields of model in json-compatible format'
    __public__ = None
    __exclude__ = None

    def to_json(self, exclude=[], include=[], only=[], convert=True, replace=False, extend={}, **kwargs):
        """
        :param exclude: 在转化时指定需要排除的字段列表
        :param include: 在转化时指定需要包含的字段列表
        :param only:    在转化时指定仅仅包含的字段列表
        :param convert: 附加转换结果显示,当需要转换值的显示成指定的状态值使用, 状态值需要在kwargs指定.\
                     {'status': {'0': u'正常', '1': u'故障',...}}, 将会在返回的字段中附加一个同名的且前面加'_'的字段,\
                     当status的值为'0'时, 那返回值会附加的'_status'字段,且'_status'字段值为u'正常'.
                    当存在外键的时候, 会获取外键中是否有'_get_public'方法,有的化将显示一个友好的值.
        :param replace: 当为True时,将不会产生_下划线的转换字段,而是直接替换
        :param extend: 扩充值, 想格式化的json字符串扩充值,主要是解决外键引用而又想显示值
        :param kwargs:
        :return:
        """
        data = {}
        items = self._sa_instance_state.attrs.items()
        column_name = self._sa_instance_state.attrs.keys()
        self.convert = convert
        self.kwargs = kwargs
        if only:
            """ If you specify the parameters of only """
            _public = set(only)
            _exclude = set([])
        else:
            if self.__public__ and self.__exclude__ is None:
                """ __public__ is True and __exclude__ is False """
                _public = self.__public__
                _exclude = []
            elif self.__public__ is None and self.__exclude__:
                """ __public__ is False and __exclude__ is True """
                _public = []
                _exclude = self.__exclude__
            elif self.__public__ and self.__exclude__:
                """ __public__ is True and __exclude__ is True """
                _exclude = self.__exclude__
                _public = set(self.__public__) - set(_exclude)
            else:
                """ __public__ is False and __exclude__ is False """
                _public = column_name
                _exclude = []
            if exclude:
                """ If you specify the parameters of exclude """
                _exclude = set(_exclude + exclude)
            if include:
                """ If you specify the parameters of include """
                _public = set(_public + include) - set(_exclude)
        for key, field in items:
            if _public and key not in _public: continue
            if key in _exclude: continue
            value = self._serialize(field.value)
            data[key] = value
            if convert and kwargs and kwargs.has_key(key):
                if replace is True:
                    _key = '%s' % key
                else:
                    _key = '_%s' % key
                data[_key] = kwargs.get(key, value)
                # data[_key] = kwargs[key].get(value, value)
        if extend:
            data.update(extend)
        return data
    
    @classmethod
    def _serialize(cls, value, follow_fk=False):
        ret = value
        if isinstance(value, datetime.datetime) or isinstance(value, datetime.date):
            ret = str(value)
        elif isinstance(value, uuid.UUID):
            ret = str(value)
        elif BaseModelMixin in value.__class__.__bases__ or SerializeMixin in value.__class__.__bases__:
            # 一对多或者多对一
            try:
                ret = value._get_public()
            except:
                pass
        elif AppenderMixin in value.__class__.__bases__:
            # 多对多
            try:
                ret = [x._get_public() for x in value.all()]
            except Exception as ex:
                print ('many to many : ', ex)
        elif hasattr(value, '__iter__'):
            # 迭代对象
            # Don't set True
            if follow_fk:
                ret = []
                for v in value:
                    ret.append(cls._serialize(v))
        return ret